﻿/* Web Site snapshot component
 * by Armen Kirakosyan
 * armen@kirakosyan.com
 */


using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace WebShooter
{
    public class Snapshot
    {
        WebBrowser wb;

        private string _url;
        private Bitmap _Bitmap;
        private Control ctrl;

        public delegate void OnSnapshotReadyHandler(Bitmap b);
        /// <summary>
        /// Occurs when snapshot is ready
        /// </summary>
        public event OnSnapshotReadyHandler OnSnapshotReady;

        /// <summary>
        /// Image format for saving as a file
        /// </summary>
        public enum ImageFormat
        {
            bmp  = 0,
            png  = 1,
            gif  = 2,
            jpeg = 3
        }

        public Snapshot()
        {
            // Some default values
            SnapshotFormat = ImageFormat.png;
            SnapshotSize   = new Size(800, 600);
            WebSiteSize    = new Size(800, 600);
        }

        /// <summary>
        /// The URL to snapshot 
        /// </summary>
        public string URL
        {
            get { return _url; }
            set 
            {
                if (value.StartsWith("http://"))
                {
                    _url = value;
                }
                else
                {
                    _url = "http://" + value;
                }
            }
        }

        public ImageFormat SnapshotFormat
        {
            get;
            set;
        }

        /// <summary>
        /// By default 600x400
        /// </summary>
        public Size SnapshotSize
        {
            get;
            set;
        }

        /// <summary>
        /// By default 1280x800
        /// </summary>
        public Size WebSiteSize
        {
            get;
            set;
        }

        /// <summary>
        /// Async method which navigates to URL and makes snapshot
        /// </summary>
        public void Make()
        {
            // Check if URL is ommited
            if ( String.IsNullOrEmpty( URL ))
            {
                throw new Exception("URL is not specified!");
            }

            wb = new WebBrowser();

            // Hide scrollbars
            wb.ScrollBarsEnabled = false;

            //turn off java script errors
            wb.ScriptErrorsSuppressed = true;

            // Initial size of the web browser
            wb.Width  = WebSiteSize.Width;
            wb.Height = WebSiteSize.Height;
            
            wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);

            wb.Navigate(URL);
            
            ctrl = new Control();
            ctrl.Size = wb.Size;
            ctrl = wb;
        }

        /// <summary>
        /// Resizes the snapshot, keeping the original one
        /// </summary>
        /// <param name="newWidth">new image width</param>
        /// <param name="newHeight">new image height</param>
        /// <returns></returns>
        public Bitmap Resize(int newWidth, int newHeight)
        {
            if (newWidth != 0 && newHeight != 0)
            {
                Bitmap temp = _Bitmap;
                Bitmap bmap = new Bitmap(newWidth, newHeight, temp.PixelFormat);

                double nWidthFactor = (double)temp.Width / (double)newWidth;
                double nHeightFactor = (double)temp.Height / (double)newHeight;

                double fx, fy, nx, ny;
                int cx, cy, fr_x, fr_y;
                Color color1 = new Color();
                Color color2 = new Color();
                Color color3 = new Color();
                Color color4 = new Color();
                byte nRed, nGreen, nBlue;

                byte bp1, bp2;

                for (int x = 0; x < bmap.Width; ++x)
                {
                    for (int y = 0; y < bmap.Height; ++y)
                    {

                        fr_x = (int)Math.Floor(x * nWidthFactor);
                        fr_y = (int)Math.Floor(y * nHeightFactor);
                        cx = fr_x + 1;
                        if (cx >= temp.Width) cx = fr_x;
                        cy = fr_y + 1;
                        if (cy >= temp.Height) cy = fr_y;
                        fx = x * nWidthFactor - fr_x;
                        fy = y * nHeightFactor - fr_y;
                        nx = 1.0 - fx;
                        ny = 1.0 - fy;

                        color1 = temp.GetPixel(fr_x, fr_y);
                        color2 = temp.GetPixel(cx, fr_y);
                        color3 = temp.GetPixel(fr_x, cy);
                        color4 = temp.GetPixel(cx, cy);

                        // Blue
                        bp1 = (byte)(nx * color1.B + fx * color2.B);

                        bp2 = (byte)(nx * color3.B + fx * color4.B);

                        nBlue = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Green
                        bp1 = (byte)(nx * color1.G + fx * color2.G);

                        bp2 = (byte)(nx * color3.G + fx * color4.G);

                        nGreen = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Red
                        bp1 = (byte)(nx * color1.R + fx * color2.R);

                        bp2 = (byte)(nx * color3.R + fx * color4.R);

                        nRed = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        bmap.SetPixel(x, y, System.Drawing.Color.FromArgb
                (255, nRed, nGreen, nBlue));
                    }
                }

                return bmap;
            }
            else
            {
                throw new Exception("Wrong paramater");
            }
        }

        void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            if (wb.ReadyState == WebBrowserReadyState.Complete)
            {
                _Bitmap = new Bitmap(WebSiteSize.Width, WebSiteSize.Height);
                ctrl.DrawToBitmap(_Bitmap, new Rectangle(new Point(0, 0), WebSiteSize));
              
                wb.Dispose();
                if (OnSnapshotReady != null)
                {
                    OnSnapshotReady(Resize(SnapshotSize.Width, SnapshotSize.Height));
                }
            }
        }

        /// <summary>
        /// The snapshot
        /// </summary>
        public Bitmap WebImage
        {
            get
            {
                return _Bitmap;
            }
        }

        /// <summary>
        /// Save the snapshot as a file
        /// </summary>
        /// <param name="FileName">Full path name of the file</param>
        public void Save(string FileName)
        {
            if (String.IsNullOrEmpty(FileName))
            {
                throw new Exception("FileName is not specified!");
            }

            System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Png;

            switch(SnapshotFormat)
            {
                case ImageFormat.bmp:
                    format = System.Drawing.Imaging.ImageFormat.Bmp;
                    break;
                case ImageFormat.gif:
                    format = System.Drawing.Imaging.ImageFormat.Gif;
                    break;
                case ImageFormat.jpeg:
                    format = System.Drawing.Imaging.ImageFormat.Jpeg;
                    break;
                case ImageFormat.png:
                    format = System.Drawing.Imaging.ImageFormat.Png;
                    break;
            }
            Resize(SnapshotSize.Width, SnapshotSize.Height).Save(FileName, format);
        }
    }
}
